#include "seven_bus_packet.h"
#include "errno.h"
#include <stdbool.h>
#include <string.h>
#include "checksum/crc16_ccitt.h"
#include "seven_bus.h"

#define RX_BUFFER_SIZE (2 * SEVENBUS_PACKET_MAX_SIZE)
#define RX_STATE_NONE (0)
#define RX_STATE_HEADER (1) //finding header
#define RX_STATE_DATA   (2) //recving data
#define RX_STATE_CRC    (3)

typedef struct {
    uint32_t write_idx;
} buff_manager_t;

static int _rx_state = RX_STATE_HEADER;
static buff_manager_t _rx_buff_ctl;
static uint8_t _rx_buff[RX_BUFFER_SIZE] = {0};  //cache 2 paket

static inline int _rx_buff_write(uint8_t data)
{
    if (_rx_buff_ctl.write_idx < RX_BUFFER_SIZE) {
        _rx_buff[_rx_buff_ctl.write_idx] = data;
        _rx_buff_ctl.write_idx++;
        return 0;
    } else {
        //overflow
        return -ENOMEM;
    }
}

static inline void _rx_buff_drop_front(uint32_t len)
{
    if (len >= _rx_buff_ctl.write_idx) {
        //drop all
        _rx_buff_ctl.write_idx = 0;
        memset(_rx_buff, 0, RX_BUFFER_SIZE);
    } else {
        //move left data to font
        memmove(_rx_buff, &_rx_buff[len], _rx_buff_ctl.write_idx - len);
        _rx_buff_ctl.write_idx -= len;
    }
}

void seven_bus_pkt_buff_init(void)
{
    memset(_rx_buff, 0, sizeof(_rx_buff));
    _rx_buff_ctl.write_idx = 0;
}

int seven_bus_pkt_buff_rx(seven_bus_dev_t *dev,  uint8_t data)
{
    int ret = 0;
    seven_bus_pkt_hdr_t *hdr = (seven_bus_pkt_hdr_t*)_rx_buff;

    switch (_rx_state) {
        case RX_STATE_NONE:
        default:
        {
            //理论上不会进入这里，但是若进入，则按照初始化处理
            _rx_buff_ctl.write_idx = 0;
            _rx_buff_write(data);
            _rx_state = RX_STATE_HEADER;
            break;
        }

        case RX_STATE_HEADER: {
            //解析header阶段，不用考虑溢出问题
            _rx_buff_write(data);
            while (_rx_buff_ctl.write_idx >= sizeof(seven_bus_pkt_hdr_t)) {
                if ((hdr->magic == SEVENBUS_PKT_HDR_MAGIC) && ((hdr->id + hdr->len + hdr->magic) == hdr->hdr_sum)) {
                    //valid header received
                    _rx_state = RX_STATE_DATA;
                } else {
                    //not a valid packet header, drop one byte from front
                    _rx_buff_drop_front(1);
                }
            }
           break; 
        }

        case RX_STATE_DATA: {
            _rx_buff_write(data);
            if (_rx_buff_ctl.write_idx >= hdr->len + sizeof(seven_bus_pkt_hdr_t)) {
                _rx_state = RX_STATE_CRC;
            }
            break;
        }

        case RX_STATE_CRC: {
            //check crc is valid
            _rx_buff_write(data);
            //大端切换
            uint16_t crc_recv = _rx_buff[_rx_buff_ctl.write_idx - 2] << 8 | _rx_buff[_rx_buff_ctl.write_idx - 1];
            //calc crc16
            uint16_t crc_calc = crc16_ccitt_false_calc(&_rx_buff[sizeof(seven_bus_pkt_hdr_t)], hdr->len);
            if (crc_calc == crc_recv) {
                //recv valid packet
                //call registered process callback
                for (int i = 0; i < dev->cb_len; i++) {
                    if (dev->cb_array[i].msg_id == hdr->id) {
                        ret = dev->cb_array[i].fn(_rx_buff);
                    }
                }
            } else {
                //not valid packet, drop one byte from head
                _rx_buff_drop_front(1);
            }
            break;
        }
    }

    return ret;
}
